package com.xjy.system.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.xjy.common.exception.CustomException;
import com.xjy.common.exception.UtilException;
import com.xjy.common.utils.PageUtils;
import com.xjy.common.core.page.PagePlus;
import com.xjy.common.core.page.TableDataInfo;
import com.xjy.system.domain.SysDepositUpdate;
import com.xjy.system.domain.SysMaterialUpdate;
import com.xjy.system.domain.bo.*;
import com.xjy.system.domain.vo.SysMaterialUpdateVo;
import com.xjy.system.service.ISysCheckaccountService;
import com.xjy.system.service.ISysFundaccountdetailService;
import com.xjy.system.service.ISysImageMngService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.xjy.common.core.mybatisplus.core.ServicePlusImpl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.xjy.system.domain.SysDeposit;
import com.xjy.system.mapper.SysDepositMapper;
import com.xjy.system.domain.vo.SysDepositVo;
import com.xjy.system.service.ISysDepositService;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.Collection;

/**
 * 押金基础信息Service业务层处理
 *
 * @author xjy
 * @date 2022-03-23
 */
@Service
public class SysDepositServiceImpl extends ServicePlusImpl<SysDepositMapper, SysDeposit> implements ISysDepositService {

	@Autowired
	private ISysFundaccountdetailService iSysFundaccountdetailService;

	@Autowired
	private ISysCheckaccountService iSysCheckaccountService;

	@Autowired
	private ISysImageMngService iSysImageMngService;

	@Override
	public SysDepositVo queryById(Long id) {
		SysDepositVo rsp = null;
		SysDepositQueryBo bo = new SysDepositQueryBo();
		bo.setId(id);
		List<SysDepositVo> list = baseMapper.queryPageList(bo);
		if (null != list && list.size() > 0) {
			rsp = list.get(0);
		}
		return rsp;
	}

	@Override
	public TableDataInfo<SysDepositVo> queryPageList(SysDepositQueryBo bo) {
		List<SysDepositVo> list = baseMapper.queryPageList(bo);
		return PageUtils.buildDataInfo(list);
	}

	@Override
	public List<SysDepositVo> queryList(SysDepositQueryBo bo) {
		return listVo(buildQueryWrapper(bo), SysDepositVo.class);
	}

	private LambdaQueryWrapper<SysDeposit> buildQueryWrapper(SysDepositQueryBo bo) {
		Map<String, Object> params = bo.getParams();
		LambdaQueryWrapper<SysDeposit> lqw = Wrappers.lambdaQuery();
		lqw.eq(bo.getProjId() != null, SysDeposit::getProjId, bo.getProjId());
		lqw.eq(bo.getContractId() != null, SysDeposit::getContractId, bo.getContractId());
		lqw.eq(bo.getResultProjId() != null, SysDeposit::getResultProjId, bo.getResultProjId());
		lqw.eq(StrUtil.isNotBlank(bo.getDepNo()), SysDeposit::getDepNo, bo.getDepNo());
		lqw.eq(bo.getDepMaxType() != null, SysDeposit::getDepMaxType, bo.getDepMaxType());
		lqw.eq(StrUtil.isNotBlank(bo.getDepNoBack()), SysDeposit::getDepNoBack, bo.getDepNoBack());
		lqw.eq(bo.getDepMinType() != null, SysDeposit::getDepMinType, bo.getDepMinType());
		lqw.eq(StrUtil.isNotBlank(bo.getDepCollecor()), SysDeposit::getDepCollecor, bo.getDepCollecor());
		lqw.eq(StrUtil.isNotBlank(bo.getDepPaior()), SysDeposit::getDepPaior, bo.getDepPaior());
		lqw.eq(StrUtil.isNotBlank(bo.getDepContent()), SysDeposit::getDepContent, bo.getDepContent());
		lqw.eq(bo.getDepAmt() != null, SysDeposit::getDepAmt, bo.getDepAmt());
		lqw.eq(bo.getDepTime() != null, SysDeposit::getDepTime, bo.getDepTime());
		lqw.eq(bo.getDepBalance() != null, SysDeposit::getDepBalance, bo.getDepBalance());
		lqw.like(StrUtil.isNotBlank(bo.getColBankName()), SysDeposit::getColBankName, bo.getColBankName());
		lqw.eq(StrUtil.isNotBlank(bo.getDepHandler()), SysDeposit::getDepHandler, bo.getDepHandler());
		lqw.eq(bo.getDepHandlerId() != null, SysDeposit::getDepHandlerId, bo.getDepHandlerId());
		lqw.eq(StrUtil.isNotBlank(bo.getColBank()), SysDeposit::getColBank, bo.getColBank());
		lqw.eq(StrUtil.isNotBlank(bo.getColBankNo()), SysDeposit::getColBankNo, bo.getColBankNo());
		lqw.eq(StrUtil.isNotBlank(bo.getDepColNo()), SysDeposit::getDepColNo, bo.getDepColNo());
		lqw.eq(StrUtil.isNotBlank(bo.getDepColImg()), SysDeposit::getDepColImg, bo.getDepColImg());
		lqw.eq(bo.getDepStatus() != null, SysDeposit::getDepStatus, bo.getDepStatus());
		lqw.eq(StrUtil.isNotBlank(bo.getReserveOne()), SysDeposit::getReserveOne, bo.getReserveOne());
		lqw.eq(StrUtil.isNotBlank(bo.getDepColpayAccount()), SysDeposit::getDepColpayAccount, bo.getDepColpayAccount());
		lqw.eq(StrUtil.isNotBlank(bo.getDepColpayNo()), SysDeposit::getDepColpayNo, bo.getDepColpayNo());
		lqw.eq(StrUtil.isNotBlank(bo.getReserveThree()), SysDeposit::getReserveThree, bo.getReserveThree());
		lqw.eq(StrUtil.isNotBlank(bo.getRemarks()), SysDeposit::getRemarks, bo.getRemarks());
		lqw.eq(bo.getDepColpayType() != null, SysDeposit::getDepColpayType, bo.getDepColpayType());
		lqw.eq(bo.getDepPayaccountId() != null, SysDeposit::getDepPayaccountId, bo.getDepPayaccountId());
		lqw.eq(StrUtil.isNotBlank(bo.getDepColpayBank()), SysDeposit::getDepColpayBank, bo.getDepColpayBank());
		lqw.eq(bo.getDepCollecorId() != null, SysDeposit::getDepCollecorId, bo.getDepCollecorId());
		lqw.eq(bo.getDepPaiorId() != null, SysDeposit::getDepPaiorId, bo.getDepPaiorId());
		lqw.eq(bo.getAuditStatus() != null, SysDeposit::getAuditStatus, bo.getAuditStatus());
		lqw.in(null != bo.getIdList() && bo.getIdList().size() > 0,SysDeposit::getId,bo.getIdList());
		return lqw;
	}

	@Override
	public Boolean insertByAddBo(SysDepositAddBo bo) {

		SysDeposit add = BeanUtil.toBean(bo, SysDeposit.class);
		validEntityBeforeSave(add);

		return save(add);
	}

	@Override
	public Boolean updateByEditBo(SysDepositEditBo bo) {
		SysDeposit update = BeanUtil.toBean(bo, SysDeposit.class);
		validEntityBeforeSave(update);
		return updateById(update);
	}

	@Transactional
	@Override
	public synchronized Boolean auditByEditBo(BaseAuditBo req) {


		boolean rsp = false;
		List<Long> idList = req.getIdList();
		if(null == idList || idList.size() == 0){
			throw new CustomException("需审核的数据不能为空！");
		}
		SysDepositQueryBo sysDepositQueryBo = new SysDepositQueryBo();
		sysDepositQueryBo.setIdList(idList);
		sysDepositQueryBo.setAuditStatus(false);
		List<SysDepositVo> sysDepositVoList = this.queryList(sysDepositQueryBo);
		if(null == sysDepositVoList || sysDepositVoList.size() == 0){
			throw new CustomException("勾选的数据审核状态已审批，无需重新审批！");
		}
		for(SysDepositVo sysDepositVo:sysDepositVoList){
			SysDeposit updateOne = new SysDeposit();
			// TODO 结账效验
			iSysCheckaccountService.check(sysDepositVo.getProjId(),sysDepositVo.getDepTime());
			updateOne.setId(sysDepositVo.getId());
			String depNo = sysDepositVo.getDepNo();
			String depNoBack = sysDepositVo.getDepNoBack();
			Integer depMaxType = sysDepositVo.getDepMaxType();
			Integer depMinType = sysDepositVo.getDepMinType();
			BigDecimal depAmt = sysDepositVo.getDepAmt();

			//押金条状态:0：未知；收取：（1：收回）；支付：（2：退还）
			Integer depStatus = sysDepositVo.getDepStatus();

			if (depAmt.compareTo(new BigDecimal(0)) <= 0) {
				throw new CustomException("押金金额必须大于0！");
			}
			//收取或者支付
			if (depMinType.equals(0)) {
				//设置余额 == 押金金额
				updateOne.setDepBalance(depAmt);
			}
			//清退或者退回
			if (depMinType.equals(1)) {
				if (StringUtils.isBlank(depNoBack)) {
					throw new CustomException("押金收取/支付之后的退回单据编号不能为空！");
				}
				SysDepositQueryBo sysDepositQueryReq = new SysDepositQueryBo();
				sysDepositQueryReq.setDepNo(depNo);
				sysDepositQueryReq.setDepMaxType(depMaxType);
				sysDepositQueryReq.setDepMinType(0);

				List<SysDepositVo> list = baseMapper.queryPageList(sysDepositQueryReq);
				if(null == list || list.size() == 0){
					throw new CustomException("未查询到收取/支付押金主信息！");
				}
				SysDepositVo main = list.get(0);
				BigDecimal depBalanceMain = main.getDepBalance();
				if(depAmt.compareTo(depBalanceMain) == 1){
					throw new CustomException("清退/退回金额不能大于剩余的金额！");
				}
				//开始计算余额并更新
				BigDecimal depBalanceNew = depBalanceMain.subtract(depAmt);
				SysDeposit updateMain = new SysDeposit();
				updateMain.setId(main.getId());
				updateMain.setDepBalance(depBalanceNew);

				//押金条状态:0：未知；收取：（1：收回）；支付：（2：退还）
				if(depBalanceNew.compareTo(new BigDecimal(0)) == 0){
					if(depMaxType.equals(0)){
						updateMain.setDepStatus(1);
					}
					if(depMaxType.equals(1)){
						updateMain.setDepStatus(2);
					}
				}
				updateMain.setDepMinType(main.getDepMinType());
				updateMain.setDepMaxType(main.getDepMaxType());
				baseMapper.updateById(updateMain);

			}

			boolean changeFundaccount = this.changeFundaccount(sysDepositVo);
			if (!changeFundaccount) {
				throw new CustomException("更新资金流水失败！");
			}
			//收取或者支付
			if ((depMinType.equals(0) && depMaxType.equals(0)) || depMinType.equals(1) && depMaxType.equals(0)) {
				this.uploadImage(sysDepositVo);
			}

			updateOne.setAuditStatus(true);
			rsp = baseMapper.updateById(updateOne) > 0;
		}


		return rsp;
	}


	private synchronized Boolean changeFundaccount(SysDepositVo req){
		Integer depMaxType = req.getDepMaxType();
		Integer depMinType = req.getDepMinType();

		SysFundaccountdetailAddBo addBo = new SysFundaccountdetailAddBo();
		//押金收取、押金退回 +
		if ((depMaxType.equals(0) && depMinType.equals(0)) || depMaxType.equals(1) && depMinType.equals(1)) {
			addBo.setCategory(0L);
			addBo.setTransactionCategory(0L);


		}
		//押金清退、押金支付 -
		if ((depMaxType.equals(0) && depMinType.equals(1)) || depMaxType.equals(1) && depMinType.equals(0)) {
			addBo.setCategory(1L);
			addBo.setTransactionCategory(1L);
		}
		addBo.setProjId(req.getProjId());
		addBo.setProjName(req.getProjName());
		addBo.setContractId(req.getContractId());
		addBo.setContractName(req.getContractName());
		addBo.setSettleProj(req.getResultProjId());
		addBo.setSettleProjName(req.getResultProjName());

		addBo.setAccId(req.getDepPayaccountId());
		addBo.setAccountName(req.getDepColpayAccount());
		addBo.setAccountBank(req.getDepColpayBank());
		addBo.setAccountNo(req.getDepColpayNo());
		if(depMinType.equals(0)){
			addBo.setTransactionId(req.getDepNo());

		}else {
			addBo.setTransactionId(req.getDepNoBack());
		}
		addBo.setSenderId(req.getDepPaiorId());
		addBo.setSender(req.getDepPaior());
		addBo.setReceiveId(req.getDepCollecorId());
		addBo.setReceive(req.getDepCollecor());
		addBo.setManagerId(req.getDepHandlerId());
		addBo.setManager(req.getDepHandler());
		addBo.setTransactionType(req.getDepColpayType());

		addBo.setTransactionDate(req.getDepTime());
		addBo.setAmount(req.getDepAmt());
		addBo.setRemarks(req.getRemarks());
		return iSysFundaccountdetailService.insertByAddBo(addBo);
	}

	private boolean uploadImage(SysDepositVo bo){
		boolean rsp = false;
		if(StringUtils.isNotBlank(bo.getDepColImg()) && !"[]".equals(bo.getDepColImg())){
			SysImageMngAddBo sysImageMngAddBo = new SysImageMngAddBo();
			sysImageMngAddBo.setAuditStatus(true);
			sysImageMngAddBo.setProjId(bo.getProjId());
			sysImageMngAddBo.setImage(bo.getDepColImg());
			sysImageMngAddBo.setType(3+"");
			sysImageMngAddBo.setOperatorId(bo.getDepHandlerId());
			sysImageMngAddBo.setOperator(bo.getDepHandler());
			sysImageMngAddBo.setOutNo(bo.getDepNo());
			rsp =  iSysImageMngService.insertByAddBo(sysImageMngAddBo);
		}
		return rsp;
	}


	/**
	 * 保存前的数据校验
	 *
	 * @param entity 实体类数据
	 */
	private void validEntityBeforeSave(SysDeposit entity) {
		//TODO 做一些数据校验,如唯一约束
		Integer depMaxType = entity.getDepMaxType();
		Integer depMinType = entity.getDepMinType();
		//收取押金
		if (depMaxType.equals(0)) {
			//清退
			if (depMinType.equals(1)) {
				String depNoBack = entity.getDepNoBack();
				if (StringUtils.isBlank(depNoBack)) {
					throw new CustomException("押金收取/支付之后的退回单据编号不能为空！");
				}
			}
		}
		//支付押金
		if (depMaxType.equals(1)) {
			//退回
			if (depMinType.equals(1)) {
				String depNoBack = entity.getDepNoBack();
				if (StringUtils.isBlank(depNoBack)) {
					throw new CustomException("押金收取/支付之后的退回单据编号不能为空！");
				}

			}
		}
		// TODO 结账效验
		iSysCheckaccountService.check(entity.getProjId(),entity.getDepTime());

	}

	@Override
	public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
		if (isValid) {
			//TODO 做一些业务上的校验,判断是否需要校验
		}
		return removeByIds(ids);
	}
}
